home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / tjgold.zip / INSTALL.004 / FGUSER16.TXT < prev    next >
Text File  |  1995-05-29  |  76KB  |  1,781 lines

  1.                              Managing Input Forms
  2.  
  3.                             "Will that Gold product ever get finished?"
  4.                                                     A. Spouse, 1995
  5.  
  6. Introduction
  7.  
  8.           Input/Output, or IO for short, is the heart of any program. As
  9.      you are about to discover, it is also the heart of Gold!
  10.  
  11.           The Gold units which support IO forms are GOLDIO, GOLDIO2 and
  12.      GOLDIO3. These units offer a full set of sophisticated input tools
  13.      including the following:
  14.  
  15.           27 different field types support string, number and date
  16.           input, along with radio buttons, checks boxes, lists and push
  17.           buttons.
  18.  
  19.           Automated input validation, e.g. only accept numbers in the
  20.           range 16 to 60; only accept dates in 1995; etc.
  21.  
  22.           Flexible picture fields allowing users to input telephone
  23.           numbers, part numbers, etc.
  24.  
  25.           A bevy of user hooks allowing the developer to fine tune the
  26.           form's behavior.
  27.  
  28.           Forms can be displayed in draggable windows.
  29.  
  30.           Exotic fields such as spinners and drop-down calendars are
  31.           available.
  32.  
  33.           All validation and error messages are customizable allowing
  34.      easy internationalization (that's localization for the politically
  35.      correct among us). Multiple simultaneous forms are supported. For
  36.      example, a secondary form can be displayed when a user clicks on a
  37.      button in the main form. Fully supports the mouse. All colors are
  38.      customizable. Fields can be grayed (or disabled) based on the
  39.      values in other fields. Oh, that's enough, you get the idea.
  40.  
  41. Building a Form -- A Quick Recipe
  42.  
  43.           Time for an analogy. You don't need to be an accredited chef
  44.      to cook breakfast (unless you happen to be French). The same goes
  45.      for IO forms -- although there is a great deal that you need to
  46.      learn to become a Form Jedi, you can still create very useful and
  47.      functional forms by following an essentially simple recipe.
  48.  
  49.           Before you delve into the form creation process, you need to
  50.      understand some of the basic principles. A form is a collection of
  51.      fields bound together to give the user a single input screen or
  52.      dialog. Fields have various uses. You might use a field to record a
  53.      person's name or zip code, allowing the end user to type text
  54.      directly into the field. Other fields don't accept normal data
  55.      entry, such as radio buttons or lists -- the user makes a choice
  56.      from a predefined set.
  57.  
  58.           If you follow a simple recipe and take the steps in the
  59.      correct order, you can create a form in just a few minutes. Here is
  60.      the recipe:
  61.  
  62.           Decide what data you want to garner from the user, and what
  63.      the data types will be.
  64.  
  65.           e.g. 5 strings for the address, an integer for the age, and a
  66.           string for the sex.
  67.  
  68.      Decide on the basic layout of the form.
  69.  
  70.           e.g. the form might have 5 fields (one below the other) to
  71.           enter the user's name and address, and a numeric field to
  72.           enter the person's age. Finally, there might be OK and Cancel
  73.           buttons on the form. Activate a form.
  74.  
  75.           A Gold form can support multiple forms, and at any one time, a
  76.      single form will be the active form, i.e. will have focus. All IO
  77.      procedures and function calls are directed at the active form.
  78.  
  79.           Add the fields to the form.
  80.  
  81.           At this stage, Gold doesn't care about each field's properties
  82.      -- just the order of the fields and the (X,Y) coordinate of each
  83.      field.
  84.  
  85.           Define the properties of each field.
  86.  
  87.           You might set the first field, for example, to be a string
  88.      field that accepts up to 30 alpha numeric characters. You will also
  89.      tie fields to specific variables. When the user enters data in the
  90.      field, the variable is automatically updated with the value
  91.      displayed in the field.
  92.  
  93.      Add optional labels and messages to each field.
  94.  
  95.           e.g. You might add the left-justified label "Name:" to the
  96.      first field .
  97.  
  98.      Assign appropriate values to the variables referenced by the form.
  99.  
  100.      Run the form and wait for user input.
  101.  
  102.      If the form is no longer required dispose of the fields.
  103.  
  104.           Figure 16.1 is the form created in DEMIO1.PAS. On the
  105.      following page is a full listing of the program along with
  106.      annotations showing each of the major steps in the recipe.
  107.  
  108.      Figure 16.1
  109.      A Basic Form
  110.  
  111.  
  112.      Let's analyze a few lines of code from the example.
  113.  
  114.      KwikAddField(1, 25,9);
  115.      KwikAddField(2, 25,11);
  116.  
  117.           These lines add fields to the form. The first field is located
  118.      at coordinates (25,9) and the second field is located at
  119.      coordinates (25,11), i.e. two lines below the first line.
  120.  
  121.      StringField(1, Name, '******************************');
  122.      SetLabel(1, LabelLeft,LabelLeft,'Full name:');
  123.  
  124.           These two lines define the properties of field one. The field
  125.      is a string field, i.e. a standard field where the user can enter
  126.      text or numbers. The variable associated with the field is named
  127.      NAME, and this variable will be assigned the string that the user
  128.      enters. The third parameter identifies the string picture. An
  129.      asterisk "*" indicates that any alphanumeric character will be
  130.      accepted in that position. The other picture characters are "!"
  131.      which forces alphas to upper case, "#" which accepts only numbers,
  132.      and "@" which accepts letters and punctuation. In this case, the
  133.      field will be 30 characters wide because there are 30 asterisks in
  134.      the picture. The second line adds a left justified label 'Full
  135.      name:' to the field -- you can see this label in Figure 16.1.
  136.  
  137.      StringField(2, Tel, '(###) ###-####');
  138.      SetLabel(2, LabelLeft,LabelLeft,'Tel:');
  139.  
  140.           These two lines define the properties of field one. This field
  141.      is also a string but the picture is formatted for telephone number
  142.      input (see Figure 16.1). The tel string will be updated with the
  143.      user input. The second line adds a left justified label of 'Tel: '
  144.      to the field.
  145.  
  146.      ButtonField(5,'   OK   ',finished);
  147.  
  148.           This line sets the fifth field to be a push button with the
  149.      text OK. When the button is pressed, the form input will be
  150.      terminated and the value Finished will be returned by the EditForm
  151.      function.
  152.  
  153.      Result := EditForm(1);
  154.  
  155.           This line instructs Gold to display the form and wait for the
  156.      user to conclude the input session. The function returns a value of
  157.      type gAction to indicate how the user ended the session. In this
  158.      example, the function might return Finished if the F10 key was
  159.      pressed or the user selected the OK button, or Escaped if the user
  160.      pressed the Esc key or selected the Cancel button.
  161.  
  162.           If you are the kind of programmer who likes to learn by
  163.      example (that's all of you, by the way), investigate the demo files
  164.      DEMIO2.PAS through DEMIO5.PAS. Each demo builds on the previous
  165.      one, and adds another degree of sophistication to the form. By the
  166.      last demo, the form is displayed in a window with field messages
  167.      displayed on the status bar, radio buttons and ... well, just take
  168.      a look for yourself.
  169.  
  170. Configuring the Form(s)
  171.  
  172.           Having learned the instant form recipe, it's time to take a
  173.      more detailed look at the entire form management process. RTFM.
  174.  
  175. Creating Multiple Forms
  176.  
  177.           Gold allows an application to have multiple forms defined at
  178.      one time, i.e. within the same scope. For example, form 1 might be
  179.      a customer name and address form, and form 2 might be an order
  180.      entry form. If you want to use more than one form at a time, you
  181.      must instruct Gold to create the number of forms you will need
  182.      using the following function:
  183.  
  184.      CreateForms(Count:byte);
  185.  
  186.           Instructs Gold to allocate enough memory for Count forms. Note
  187.      that Count must be in the range 1 to MaxForms (which is defined in
  188.      GOLDIO as 10). This should be called before any other IO procedures
  189.      and functions.
  190.  
  191.           If you call any Gold IO procedure or function before you call
  192.      CreateForms, Gold will assume that you will only be using one form,
  193.      and will call CreateForms(1) internally. That is why the example on
  194.      page 17-4 didn't use a CreateForms statement.
  195.  
  196.           It is important to realize that you do not need to create more
  197.      than one form just because you intend to use more than one type of
  198.      form in your application. You can use the same form for more than
  199.      one purpose if you dispose of the first set of fields and redefine
  200.      a new set of fields prior to displaying the revised form -- more
  201.      about field disposing later.
  202.  
  203.           If you want to call CreateForms more than once in an
  204.      application (and this will be rare), you must ensure that the you
  205.      call DisposeForms before calling CreateForms a second time.
  206.  
  207. Giving a Form Focus
  208.  
  209.           If you don't make a call to CreateForms, then you don't need
  210.      to worry about form focus. If your application creates more than
  211.      one form, read on.
  212.  
  213.           The notion of focus is used in many parts of Gold: the top
  214.      window on the desktop has focus, and in list applications, a
  215.      specific single or double linked list has focus. The same goes for
  216.      input forms. If you have more than one form in an application, Gold
  217.      needs to know which form to work on, i.e. which form has focus.
  218.  
  219.      The following procedure sets the focus to a specified form:
  220.  
  221.      ActivateForm(FormNo:byte);
  222.  
  223.           Instructs Gold to direct all IO procedures and functions
  224.      toward the specified form. The form must fall within the range 1 to
  225.      the value specified in the call to CreateForms.
  226.  
  227.           The following code fragment shows how ActivateForm might be
  228.      used to configure multiple forms:
  229.  
  230.           begin
  231.              CreateForms(4);
  232.              ActivateTable(1);
  233.              ...{work on form 1}
  234.              ActivateForm(2);
  235.              ...{work on form 2}
  236.           end;
  237.  
  238. Creating Dialogs, i.e. Forms in Windows
  239.  
  240.           If you are using forms (in windows) on the desktop, then refer
  241.      to the section Launching Forms on the Desktop at the end of this
  242.      chapter. The text below refers to forms created outside of the
  243.      desktop environment.
  244.  
  245.           By default, the Gold form routines are configured to work full
  246.      screen. If you want to display a form in a window you must advise
  247.      Gold that the form will be displayed in a window before calling the
  248.      field definition functions like AddField, StringField, etc.
  249.  
  250.           Use the procedure SetFormWindow (defined below) to configure
  251.      the form to run in a window.
  252.  
  253.      SetFormWindow(X1,Y1,X2,Y2,style:byte);
  254.  
  255.           Instructs Gold to create a form in a window. The first four
  256.      parameters define the window coordinates, and the fifth parameter
  257.      defines the window style.
  258.  
  259.           Having set the form window, the function FormWinNum will
  260.      return the window handle (or number). You can customize (and write
  261.      to) a form window, just like any standard Gold window.
  262.  
  263.      The following code fragment is from the demo file DEMIO10.PAS:
  264.  
  265.           procedure SetFields;
  266.           {}
  267.           var I : Integer;
  268.           begin
  269.              CreateForms(1);
  270.              ActivateForm(1);
  271.              {define the form's window}
  272.              SetFormWindow(15,4,67,22,1);
  273.              WinSetTitle(FormWinNum,' Customer Comments ');
  274.              WinSetType(FormWinNum,WMove);
  275.              WinSetShowNum(FormWinNum,false);
  276.              KwikAddField(1,10,2);
  277.              KwikAddField(2,10,14);
  278.              KwikAddField(3,35,14);
  279.              KwikAddField(4,35,16);
  280.              ...
  281.           end;
  282.  
  283.  
  284.           Gold will dispose of the window automatically when you call
  285.      DisposeFields.
  286.  
  287. Customizing a Form's Appearance and Behavior
  288.  
  289. Overriding the Form Navigation Keys
  290.  
  291.           Most of a form's characteristics are controlled by the
  292.      individual fields in a form. The keys used to jump from field to
  293.      field, however, are set for the entire table.
  294.  
  295.           By default, the keystrokes to shift to the next field up,
  296.      down, left and right are the Up cursor, Down cursor, Ctrl-Left
  297.      cursor and Ctrl-Right cursor respectively. The de facto standard of
  298.      using the Tab and Shift-Tab keys to move to the next and previous
  299.      fields are also supported.
  300.  
  301.           The F10 key is assigned to be the finished key, Esc is the
  302.      escaped key, and Ctrl-E is the erase field key.
  303.  
  304.           You can customize these keys using one of the following three
  305.      procedures:
  306.  
  307.      AssignActionChars(Nxt,Prv,U,D,L,R,Fin,Esc,E: word);
  308.  
  309.           Defines the keys the user will use to navigate the form. These
  310.      nine word parameters represent the key codes to move to the next
  311.      field, the previous field, the field above the field below, the
  312.      field to the left, the field to the right, the key to finish
  313.      editing, the key to abort editing and the key to erase the entire
  314.      field contents, respectively.
  315.  
  316.           Here is a little tip; if you pass a keycode of zero, the
  317.      keystroke assignment for that key will not be changed. This
  318.      provides a quick and easy way to change some, but not all, of the
  319.      key codes. For example, the following statement will only redefine
  320.      the up, down, left and right keys:
  321.  
  322.      AssignActionChars(0,0,278,288,294,275,0,0,0);
  323.  
  324.      AssignFinishChar(W:word);
  325.  
  326.           Provides a quick way to change the finished editing key, which
  327.      defaults to F10.
  328.  
  329.      AllowEsc(On:boolean);
  330.  
  331.           Controls whether the user can Esc from the form. Pass TRUE to
  332.      enable the Esc key, and FALSE to disable it.
  333.  
  334. Customizing Colors
  335.  
  336.           There are many different colors that might be used in a form.
  337.      In fact there are 37 tint elements that affect forms and they are
  338.      defined as follows:
  339.  
  340.           IOEditErase,
  341.           IOEditNorm,
  342.           IOEditHi,
  343.           IOEditOff,
  344.           IOButtonNorm,
  345.           IOButtonNormHot,
  346.           IOButtonHi,
  347.           IOButtonHiHot,
  348.           IOButtonOff,
  349.           IOButtonDef,
  350.           IOButtonDefHot,
  351.           IOMessage,
  352.           IOLabelNorm,
  353.           IOLabelNormHot,
  354.           IOLabelHi,
  355.           IOLabelHiHot,
  356.           IOLabelOff,
  357.           IOWinBorder1,
  358.           IOWinBorder2,
  359.           IOWinTitle,
  360.           IOWinBody,
  361.           IOWinIcons,
  362.           IOWinBorderOff,
  363.           IOCheckArea,
  364.           IOChoiceHi,
  365.           IOChoiceHiHot,
  366.           IOChoiceNorm,
  367.           IOChoiceNormHot,
  368.           IOChoiceOff,
  369.           IOIcons,
  370.           IOIcons2,
  371.           IOListHi,
  372.           IOListHiHot,
  373.           IOListNorm,
  374.           IOListNormHot,
  375.           IOListOff,
  376.           IOListScroll
  377.  
  378.           If you want to change the color of all the forms in your
  379.      application, then you should call the GoldSetColor function and
  380.      modify the Gold defaults, prior to calling any of the IO procedures
  381.      and functions. If you want to change the colors for a specific
  382.      form, then call the IOSetColor function which is defined as
  383.      follows:
  384.  
  385.      IOSetColor(A:TintElement;C:byte);
  386.  
  387.      Changes the color of a single element of the active form.
  388.  
  389.           Listed below is an extract from the demo file DEMIO6.PAS which
  390.      customizes the colors in a form.
  391.  
  392.           procedure CustomizeColors;
  393.           {}
  394.           begin
  395.              IoSetColor(IOEditErase,WhiteonRed);
  396.              IoSetColor(IOEditNorm,WhiteOnMagenta);
  397.              IoSetColor(IOEditHi,YellowOnGreen);
  398.              IoSetColor(IOEditOff,LightgrayOnMagenta);
  399.              IoSetColor(IOButtonNorm,WhiteOnBlue);
  400.              IoSetColor(IOButtonNormHot,YellowOnBlue);
  401.              IoSetColor(IOButtonHi,WhiteOnRed);
  402.              IoSetColor(IOButtonHiHot,YellowOnRed);
  403.              IoSetColor(IOButtonOff,WhiteOnBlack);
  404.              IoSetColor(IOButtonDef,LightgrayOnBlue);
  405.              IoSetColor(IOButtonDefHot,LightcyanOnBlue);
  406.              IoSetColor(IOMessage,WhiteOnBlack);
  407.              ...
  408.           end; { CustomizeColors }
  409.  
  410. Understanding Field Rules
  411.  
  412.           The field rules define the characteristics of the field. For
  413.      example, whether the field is right justified or left justified.
  414.      The rules are stored for each field individually, and the
  415.      programmer can change any or all of the rules as desired.
  416.  
  417.      There are five different field rules, defined as follows:
  418.  
  419.           AllowNull - indicates the user is allowed to leave the field
  420.                empty.
  421.           SuppressZero - the field is displayed as blank in a number
  422.                field if the value is zero.
  423.           RightJustify - the field grows from right to left rather than
  424.                the normal left to right.
  425.           EraseDefault - when the user enters the field, the default (or
  426.                previous value) is erased if the user presses a normal
  427.                alphanumeric key.
  428.           JumpIfFull - move to the next field to the right if the field
  429.                is filled with data, i.e. if the user has entered
  430.                sufficient characters to fill the field.
  431.  
  432.           These five values are defined as constants in GOLDIO.PAS, and
  433.      can be summed to combine field rules. For example, a field may be
  434.      defined as having rules AllowNull + SuppressZero. If one of the
  435.      constants is omitted from a field rule's declaration, then that
  436.      rule will not be enforced. In the example just mentioned, for
  437.      example, the field would not be right justified.
  438.  
  439.           If you want none of the rules to apply, then specify the
  440.      constant NoRules as the only field rule.
  441.  
  442.           To set the default rules for an entire form, call the
  443.      following procedure before adding the fields:
  444.  
  445.      SetDefaultRules(Rules:word);
  446.  
  447.           Defines the default rules that will be applied to any fields
  448.      subsequently created with AddField.
  449.  
  450. Miscellaneous Form Defaults
  451.  
  452.           The following procedures and functions are used to set other
  453.      default characteristics of a form:
  454.  
  455.      SetMessageXY(X,Y:byte; InWindow: boolean);
  456.  
  457.           Defines the location of where field messages will be
  458.      displayed. These messages provide the user with information about
  459.      the field with focus. For example, a message might be "Enter an age
  460.      in the range 15 to 65". If the form is being displayed in a window,
  461.      and the message will be displayed inside the window, set the
  462.      InWindow parameter to TRUE, otherwise set it to false.
  463.  
  464.      SetInsertMode(On:boolean);
  465.  
  466.           Controls whether the user is initially in insert or overtype
  467.      mode. Pass TRUE to start the form in insert mode.
  468.  
  469.      SetValidation(Val:gValidate);
  470.  
  471.           Gold offers automatic field validation on numeric and date
  472.      fields. The validation checks can be performed when the user moves
  473.      from one field to the next, or when the user attempts to finish
  474.      input (by clicking on the OK button, or pressing F10, for example).
  475.      The procedure accepts one of the following two values:
  476.  
  477.      gValidate = (ValidatebyField,ValidateAtEnd);
  478.  
  479.  
  480. Placing Fields in a Form
  481.  
  482.           Having defined the form's main properties, you need to place
  483.      the fields on the form. At this point Gold doesn't need to know
  484.      anything about the field except where it is positioned, and which
  485.      fields will be adjacent to it.
  486.  
  487.      AddField(FieldID,DefU,DefD,DefL,DefR,DefX,DefY:byte);
  488.  
  489.           Adds a field to a form. The first parameter identifies the
  490.      logical field number. This must be unique, and it is recommended
  491.      that the fields are added in ascending numerical order. This same
  492.      field identifier is used in subsequent calls to change the field's
  493.      properties. The next four parameters identify the field ID of the
  494.      fields which will be jumped to when the user attempts to navigate
  495.      upward, downward, leftward and rightward, respectively. The final
  496.      two parameters identify the (X,Y) coordinate of the first character
  497.      of the field.
  498.  
  499.      KwikAddField(FieldID,DefX,DefY:byte);
  500.  
  501.           Performs the same function as AddField but leaves Gold to
  502.      assign the field jumps. Upward and leftward will jump to the field
  503.      whose ID is one less than the current field. Downward and rightward
  504.      will jump to the field whose ID is one greater than the current
  505.      field. Don't use this function to add the last field in a form,
  506.      since there will not be a field with an ID greater than the current
  507.      field -- use KwikAddLastField below.
  508.  
  509.      KwikAddLastField(FieldID,DefX,DefY:byte);
  510.  
  511.           Adds the last field to a form. See KwikAddField above.
  512.  
  513.           One family of fields, invisible fields, cannot be added with
  514.      any of the three functions described above. They are not visible
  515.      and so do not have (X,Y) coordinates, and the user never lands on
  516.      or edits them. These fields are referred to as HotKey fields, and
  517.      are added to the form using the following procedure:
  518.  
  519.      AddHotKeyField(FieldID:byte; Key:word; Action:gAction);
  520.  
  521.           Adds a hotkey (non-visible) field to a form. The first
  522.      parameter identifies the field ID, the second parameter the word
  523.      value of the hotkey, and the third value identifies the action code
  524.      invoked when the user presses the specified key. Listed below is
  525.      the enumerated type gAction defined in GOLDIO.PAS.
  526.  
  527.           gAction = (None,NextField,PrevField,NextForm,PrevForm,
  528.           Refresh,Enter,Help,Stop1,Stop2,...Stop97,Stop98,Stop99,
  529.           Finished,Cancel1,Cancel2,Cancel3,Cancel4,Cancel5,
  530.           Cancel6,Cancel7,Cancel8,Cancel9,Escaped);
  531.  
  532.           The following three functions apply to all visible fields, and
  533.      can be used to set field messages, labels and hotkeys:
  534.  
  535.      SetMessage(FieldID,X,Y:integer; Str : string);
  536.  
  537.           Defines the message which will be displayed when the field has
  538.      focus. The message location is controlled by using the procedure
  539.      SetMessageXY, discussed earlier.
  540.  
  541.      SetLabel(FieldID,X,Y:integer; Str : string);
  542.  
  543.           Identifies a label that will be printed when the form is
  544.      displayed. In most forms each field will have a label. Although you
  545.      can specify an explicit XY location, to literally put the label
  546.      anywhere on the form, in most situations, use the constant
  547.      LabelLeft or LabelTop to instruct Gold to automatically position
  548.      the label relative to the field.
  549.  
  550.      SetHK(FieldID:byte; Hotkey: word);
  551.  
  552.           Defines the keystroke which a user can press to automatically
  553.      jump to the field. The keystroke should normally correspond to a
  554.      highlighted letter in the field label. For example, if the letter A
  555.      is highlighted, the hotkey would be assigned as AltA, i.e. 286.
  556.  
  557. Individual Field Rules
  558.  
  559.           SetDefaultRules defines the default field input rules for a
  560.      form. Individual field rules can be specified using the procedure
  561.      FieldRules. In addition to identifying the field rules as discussed
  562.      earlier, the FieldRules procedure can control the specific
  563.      characters which the user will be allowed to input. These character
  564.      rules go beyond the simple field masks such as @, *, ! and #.
  565.  
  566.           For example, the only valid characters for a field that
  567.      identifies a warehouse part number may be "A B C 1 2 3 4 5 6".
  568.      Alternatively, a field that is a filename may allow any
  569.      alphanumeric character except the * and ? characters. Both of these
  570.      conditions can be accommodated using the FieldRules procedure
  571.      defined as follows:
  572.  
  573.      FieldRules(FieldID:byte;Rules:word;AChar:IOcharset;
  574.                                                   DChar:IOcharset);
  575.  
  576.           Defines the field rules for a specific field. The second
  577.      parameter identifies the field rules and can be any combination of
  578.      AllowNull, SuppressZero, RightJustify, EraseDefault and JumpIfFull.
  579.      The third parameter is of type set of char and identifies the
  580.      allowable characters. These characters should be defined within
  581.      square parentheses, e.g. ['A'..'C','1'..'6']. The constant [NoChar]
  582.      can be used to indicate that no special character restrictions
  583.      apply. The fourth parameter is also of type set of char and
  584.      identifies disallowed characters, e.g. ['*','?']. If no characters
  585.      are to be disallowed, use the constant [NoChar].
  586.  
  587. Controlling Field States
  588.  
  589.           The following two procedures are used to set and get the state
  590.      of a field, i.e. whether the field is enabled, disabled or hidden.
  591.      As you might imagine, hidden fields are not visible and cannot have
  592.      focus. Disabled fields, however, are visible but are displayed in a
  593.      grayed style, and cannot have focus. The gActiveState is an
  594.      enumerated type defined in GOLDIO.PAS as follows:
  595.  
  596.      gActiveState = (FldOff, FldOn, FldHidden);
  597.  
  598.      FieldSetState(FieldID:byte; State:gActiveState);
  599.  
  600.      Sets the state of the field to enabled, disabled or hidden.
  601.  
  602.      FieldGetState(FieldID:byte):gActiveState;
  603.  
  604.      Returns the state of the specified field.
  605.  
  606. Defining Each Field's Properties
  607.  
  608.           Typical fields allow the user to enter text or numbers, but
  609.      there are also radio buttons, check boxes, push buttons, etc.
  610.  
  611.           Having placed the fields on the form (with AddField or
  612.      KwikAddField), you must now define each field's properties. For
  613.      example, field 1 might accept text input, and field 2 might be a
  614.      push button, etc. Gold includes 27 different field types for your
  615.      programming pleasure and they are organized into the following
  616.      categories:
  617.  
  618.           String Fields
  619.           Number Fields
  620.           Date Fields
  621.           Push Buttons
  622.           Radio Buttons and Check Boxes
  623.           List Fields
  624.           Multi-Line Edit Fields
  625.           Hot Spots
  626.  
  627. Understanding Field Formats
  628.  
  629.           All the standard fields (i.e. string, number and date fields)
  630.      accept a string variable called DefFormat. This string uses Gold's
  631.      special mask characters to define the field's width and optionally
  632.      any mask characters, i.e. characters which are displayed in the
  633.      input field, but are non-editable, and the cursor automatically
  634.      jumps past these mask characters.
  635.  
  636.      There are four pre-defined format characters in Gold:
  637.  
  638.           #    Allow 0..9, '.','-', and 'e' for scientific
  639.  
  640.           @    Only letters of the alphabet and punctuation
  641.  
  642.           *    Any character the user can find!
  643.  
  644.           !    Like @, but all characters are converted to uppercase
  645.  
  646.           Any other characters identified in the field's format string
  647.      are treated as fixed and for display only. For example, if the
  648.      input field is a telephone number, then the format might be defined
  649.      as '(###) ###-####'. The user will only be allowed to input
  650.      numbers, and after typing three numbers, the cursor will jump three
  651.      positions to the right (to the next # character).
  652.  
  653.           As you may recall, every field is associated with an
  654.      individual variable. Note that this variable is not updated with
  655.      the formatting characters. For example, if the input field on the
  656.      screen displayed "(409) 737-5472" the variable would be updated
  657.      with the string "4097375472. This saves space if the variables are
  658.      stored in a database.
  659.  
  660.           The GoldSTR unit contains the function PicFormat which is
  661.      passed a string and a picture, and which returns the combined
  662.      formatted string.
  663.  
  664. String Fields
  665.  
  666.           The string fields form the backbone of user input forms as
  667.      they are used to gather string data from the user, e.g. names,
  668.      addresses, part numbers, etc. Two different string field types are
  669.      provided for your coding pleasure: a StringField is of fixed width
  670.      and supports the formatting characters; the ScrollField allows the
  671.      user to input a string that is wider than the displayed field
  672.      width, but does not support special formatting characters. The
  673.      fields are defined as follows:
  674.  
  675.      StringField(FieldID:byte;var Strvar:String;DefFormat:string);
  676.  
  677.           Basic input field allowing the user to input a string. The
  678.      width of the field is defined by the DefFormat parameter. For
  679.      example, a twelve character name field might be defined with a
  680.      DefFormat of '************' or a shortcut would be to use the
  681.      Replicate function, i.e. Replicate(12,'*');
  682.  
  683.      ScrollField(FieldID:byte; var Strvar:string;FieldL,MaxL:byte);
  684.  
  685.           Accepts string input and provides scrolling features, allowing
  686.      the user to input more characters than the visible field width. Use
  687.      this field type when you have limited space on the form, or when
  688.      you want to allow the user to enter a large number of characters,
  689.      and don't want a humongo field displayed. The last two parameters
  690.      define the visible field width and the maximum number of characters
  691.      which the user may input, respectively.
  692.  
  693. Number Fields
  694.  
  695.           As you might imagine, number fields should be used when you
  696.      want the user to input a number. A variety of different field types
  697.      are provided. The ByteField, WordField, IntegerField, LongIntField
  698.      procedures all accept whole numbers, and are defined as follows:
  699.  
  700.      ByteField(FieldID:byte;var Bytevar:Byte;DefFormat:string;
  701.                                                         Min,Max:byte);
  702.  
  703.      WordField(FieldID:byte;var Wordvar:Word;DefFormat:string;
  704.                                                         Min,Max:word);
  705.  
  706.      IntegerField(FieldID:byte;var Integervar:Integer;DefFormat:string;
  707.                                                       Min,Max:Integer);
  708.  
  709.      LongIntField(FieldID:byte;var LongIntvar:LongInt;DefFormat:string;
  710.                                                     Min,Max : LongInt);
  711.  
  712.           The DefFormat passed to these four fields defines the field
  713.      width and although mask characters are supported, you will
  714.      typically use the # character to indicate that numbers should be
  715.      input.
  716.  
  717.           Each of the four field types accepts Min and Max numbers
  718.      indicating the valid number range that you want to impose on the
  719.      user. For example, an age field might be set to accept ranges from
  720.      age 12 to age 65. If one of the Min or Max values is non zero, Gold
  721.      will automatically impose the range restrictions. The brighter
  722.      among you may have deduced that the Min and Max should both be set
  723.      to zero when you want to accept any number supported by the
  724.      variable type.
  725.  
  726.           Some modern applications provide spinner icons to allow the
  727.      user to quickly scroll through a number series. Gold provides the
  728.      SpinLongField function for this purpose (defined below). If you
  729.      want the user to input a whole number within a specific range, and
  730.      offer spinners, then use SpinLongField, but remember that the
  731.      variable must be of type LongInt.
  732.  
  733.      SpinLongField(FieldID:byte; var LongIntvar:LongInt;Width:byte;
  734.                                          Min,Max,Increment : LongInt);
  735.  
  736.           Gold provides two field types for the entry of real numbers.
  737.      Use FixedRealField to get input when there are a fixed number of
  738.      decimal places required. For example, a FixedRealField would be
  739.      ideal for inputting dollar values where two decimal places would be
  740.      used for the cents. If, on the other hand, the number of decimal
  741.      places is at the discretion of the user, use a RealField, because
  742.      the user can enter the decimal point (or whatever obscure character
  743.      your country may utilize for this purpose!) where appropriate.
  744.  
  745.      RealField(FieldID:byte;var Realvar:extended;DefFormat:string;
  746.                                                       Min,Max:extended);
  747.  
  748.      FixedRealField(FieldID:byte; var Realvar:Extended;Whole,DP:byte;
  749.                                                       Min,Max:extended);
  750.  
  751.           As the name suggests, the SpinRealField (defined below)
  752.      provides real field input with spinners. The last parameter defines
  753.      how much the input number will be incremented or decremented when
  754.      the spinner is clicked.
  755.  
  756.      SpinRealField(FieldID:byte; var Realvar:extended;Whole,DP:byte;
  757.                                                 Min,Max,Delta:extended);
  758.  
  759. Date Fields
  760.  
  761.           While Gold won't make you more attractive to the opposite sex,
  762.      it will allow you to get dates from your users! Gold supports eight
  763.      different date formats, which are identified using the gDate
  764.      enumerated type defined in GoldDate as follows (see Chapter 19):
  765.  
  766.      gDate = (MMDDYY,MMDDYYYY,MMYY,MMYYYY,DDMMYY,DDMMYYYY,
  767.                                                       YYMMDD,YYYYMMDD);
  768.  
  769.           You can use one of four different field types to garner date
  770.      information from the user. The traditional DateField allows the
  771.      user to input a date using the keyboard, the traditional way. The
  772.      SpinDateField adds spinners to the standard date field, allowing
  773.      the user to easily scroll backwards and forwards through dates.
  774.  
  775.           If you want the user to optionally select the date from a
  776.      pop-up calendar (and let's face it, who wouldn't?!), use the
  777.      DropDateField. This field sports an arrow to the right of the
  778.      field. When the user clicks on the arrow, a calendar is displayed.
  779.      If you want spinners and a pop-up calendar, you guessed it, use the
  780.      SpinDropDateField. These four fields are defined as follows:
  781.  
  782.      DateField(FieldID:byte;var Datevar:Dates;DateFormat:gDate;
  783.                                       DefFormat:string;Min,Max : Dates);
  784.  
  785.      SpinDateField(FieldID:byte; var Datevar:Dates;
  786.                     DateFormat:gDate;DefFormat:string; Min,Max : Dates);
  787.  
  788.      DropDateField(FieldID:byte; var Datevar:Dates;
  789.                     DateFormat:gDate;DefFormat:string; Min,Max : Dates);
  790.  
  791.      SpinDropDateField(FieldID:byte;var Datevar:Dates; DateFormat:gDate;
  792.                                      DefFormat:string; Min,Max : Dates);
  793.  
  794.           Each date field takes a variable of type dates. As with the
  795.      number fields, the Min and Max variables define the earliest and
  796.      latest dates which you will allow the user to input. (These dates
  797.      are Julian; refer to Chapter 19 to find out more about Julian
  798.      dates.) Specify a Min and Max of zero if you want to accept any
  799.      valid date. Note that Gold will always ensure that the date is
  800.      valid, e.g. November 31st, 1956 would not be accepted.
  801.  
  802.           Each of the four date fields accepts a DefFormat string. This
  803.      parameter is primarily offered for backward compatibility and to
  804.      provide support for other date formats not intrinsically supported
  805.      by Gold. Typically, pass a null string as the DefFormat and Gold
  806.      will assign the appropriate picture characters based on the
  807.      DateFormat specified.
  808.  
  809. Push Buttons
  810.  
  811.           Push button fields don't accept direct user input, i.e. you
  812.      can't enter data into a "button". Button fields, therefore, are not
  813.      linked to a variable. Each button added to a form has an action
  814.      code of type gAction. When the user presses the button, the
  815.      button's action code is processed. This results in the form editing
  816.      session finishing, and the action code returned by the form is the
  817.      action code assigned to the button. You may recall that gAction is
  818.      defined in the GoldIO unit as follows:
  819.  
  820.           gAction = (None,NextField,PrevField,NextForm,PrevForm,
  821.           Refresh,Enter,Help,Stop1,Stop2,...Stop97,Stop98,Stop99,
  822.           Finished,Cancel1,Cancel2,Cancel3,Cancel4,Cancel5,
  823.           Cancel6,Cancel7,Cancel8,Cancel9,Escaped);
  824.  
  825.           Buttons can be added to a form using ButtonField or
  826.      ButtonDefaultField, which are defined as follows:
  827.  
  828.      ButtonField(FieldID:byte; Face:string; Action:gAction);
  829.  
  830.      ButtonDefaultField(FieldID:byte; Face:string; Action:gAction);
  831.  
  832.           The second parameter identifies the text that will be
  833.      displayed on the button, and the third parameter is the gAction
  834.      code that will be returned by the form when the button is pressed.
  835.      Use the ButtonDefaultField to identify a button which will be
  836.      "pressed" when the user presses the Enter key -- there should only
  837.      be one default button field on a form.
  838.  
  839.           The ButtonChangeSettings procedure (defined below) can be used
  840.      to dynamically change the face and action code of a button. This
  841.      might be used, for example, to change an "Edit" button to a "Save"
  842.      button when the button is pressed.
  843.  
  844.      ButtonChangeSettings(FieldID:byte; Face:string; Action:gAction);
  845.  
  846.  
  847.           The following code fragments are from the demo file
  848.      DEMIO13.PAS which uses buttons to help the user tag and untag
  849.      selections in another field.
  850.  
  851.           procedure SetFields;
  852.           {}
  853.           begin
  854.              .....
  855.              KwikAddField(1, 1,2);
  856.              KwikAddField(2, 6,19);
  857.              KwikAddField(3, 18,19);
  858.              KwikAddField(4, 33,19);
  859.              KwikAddField(5, 49,19);
  860.              KwikAddLastField(6, 62,19);
  861.              AssignHindHook(HindHook);
  862.              {The List}
  863.              FillTheList;
  864.              ConfiguretheListFormat;
  865.              ListAssignSLL(ListFormat,SourceList);
  866.              WrapListField(1,75,1,14,ListFormat);     {Buttons}
  867.              ButtonField(2,'  ~T~ag  ',Stop1);
  868.              ButtonField(3,' Tag ~A~ll  ',Stop2);
  869.              ButtonField(4,' ~U~ntag all ',Stop3);
  870.              ButtonDefaultField(5,'   ~O~K   ',finished);
  871.              ButtonField(6,' ~C~ancel ',escaped);
  872.              SetHK(2,276); {Alt+T}
  873.              SetHK(3,286); {Alt+A}
  874.              SetHK(4,278); {Alt+U}
  875.              SetHK(5,280); {Alt+O}
  876.              SetHK(6,302); {Alt+C}
  877.           end; {SetFields}
  878.  
  879.           repeat
  880.              DisplayAllFields;
  881.              EditAction := EditForm(1);
  882.              case EditAction of
  883.                 Stop1: begin
  884.                    ItemIsTagged := SLLGetTagState
  885.                                     (ListFormat.ActiveNode);
  886.                    SLLSetBit(SLLNodePtr(ListFormat.ActiveNode),
  887.                              TagBit, not ItemIsTagged);
  888.                    SLLSetBit(SLLNodePtr(ListFormat.ActiveNode),
  889.                              ColBit, not ItemIsTagged);
  890.                    end;
  891.                 Stop2: begin
  892.                    SetTagAll(ListFormat,true);
  893.                 end;
  894.                 Stop3: begin
  895.                    SetTagAll(ListFormat,false);
  896.                 end;
  897.              end; {case}
  898.              CheckTagButton;
  899.           until EditAction in [Finished,Escaped];
  900.  
  901.           Note that the form is displayed in a repeat loop -- every time
  902.      a button is pressed the EditForm function (discussed later) returns
  903.      the value of the button pressed by the user. Although the user
  904.      isn't aware of it, the form is being closed and opened many times
  905.      during the edit session.
  906.  
  907. Radio Buttons and Check Boxes
  908.  
  909.           Two common elements of contemporary input forms are check
  910.      boxes and radio buttons. Both these objects provide ways of
  911.      choosing items from collections of options.
  912.  
  913.           A check box field provides a list of options with each item
  914.      having its own check box displayed to the left of the item, e.g.
  915.      [X] Toast. Any number of items in the list can be selected. An
  916.      item's selection status is toggled by hitting the space bar (even
  917.      with your forehead) or by clicking the mouse cursor on it. Selected
  918.      items have an X in the adjacent check box.
  919.  
  920.           Radio buttons are similar to check boxes, except that only one
  921.      item can be selected at any one time. When an item is selected, the
  922.      previously selected item is deselected. The selected item has a dot
  923.      in the "button" next to it, e.g. (.) Ham Sandwich.
  924.  
  925. Radio Buttons
  926.  
  927.           To define a radio button field, you must define the field
  928.      using RadioField, and then call RadioAddItem once for each option
  929.      in the field. These procedures are defined as follows:
  930.  
  931.      RadioField(FieldID,width,depth:byte; var SelectedItem:byte);
  932.  
  933.           The Width and Depth fields define the overall dimensions of
  934.      the radio button field, in characters and lines, respectively --
  935.      this is analogous to defining the groupbox in Windows (just a note
  936.      for you Delphi jocks). The SelectedItem variable indicates which
  937.      radio button is selected by the user. Be sure to assign a suitable
  938.      value to this variable before running the form.
  939.  
  940.      RadioAddItem(FieldID,ItemX,ItemY:integer; Str,Msg:string;
  941.                                                           ItemHK:word);
  942.  
  943.           Defines a specific item in a Radio field. Note the ItemX and
  944.      ItemY parameters define the position of the item relative to the
  945.      topleft of the Radio field (not the top left of the form).
  946.  
  947. CheckFields
  948.  
  949.           To define a check button field, you must define the field
  950.      using CheckField, and then call CheckAddItem once for each option
  951.      in the field. These procedures are defined as follows:
  952.  
  953.      CheckField(FieldID,width,depth:byte);
  954.  
  955.           The Width and Depth fields define the overall demensions of
  956.      the radio button field, in characters and lines, respectively.
  957.  
  958.      CheckAddItem(FieldID,ItemX,ItemY:integer; Str,Msg:string;
  959.  
  960.      ItemHK:word;var gResult:boolean);
  961.  
  962.           Defines a specific item in a Check field. Note the ItemX and
  963.      ItemY parameters define the position of the item relative to the
  964.      topleft of the Radio field (not the top left of the form). The
  965.      gResult variable is set to true when the item is checked, and false
  966.      when it is not checked.
  967.  
  968. Disabling Radio or Check Button Items
  969.  
  970.           If you want one element of a radio button or check box field
  971.      to be disabled, use CheckRadioSetActive which is defined as
  972.      follows:
  973.  
  974.      CheckRadioSetActive(FieldID,ItemNum:integer;IsActive:boolean);
  975.  
  976.           Sets the enabled state of an individual radio button or check
  977.      box item. The ItemNum parameter represents the individual element
  978.      whose state will be changed -- the first added item has a value of
  979.      1, the second a value of 2, and so on.
  980.  
  981.           The following code fragment is from the demo file DEMIO6.PAS,
  982.      and show how to construct radio button and checkbox fields:
  983.  
  984.           {Radio Buttons}
  985.           RadioField(9, 25,4,Cust.Radio);
  986.           RadioAddItem(9, 1,1, 'Corporation','',0);
  987.           RadioAddItem(9, 1,2, 'S Corporation','',0);
  988.           RadioAddItem(9, 1,3, 'DBA','',0);
  989.           RadioAddItem(9, 1,4, 'Individual','',0);
  990.           SetLabel(9,LabelTop,LabelTop,'Business ~T~ype');
  991.           SetHK(9,276);
  992.           {Check Boxes}
  993.           CheckField(10, 25,4);
  994.           CheckAddItem(10, 1,1, 'Small Business','',0,
  995.                        Cust.Check1);
  996.           CheckAddItem(10, 1,2, 'Minority Owned','',0,
  997.                        Cust.Check2);
  998.           CheckAddItem(10, 1,3, 'English Owned','',0,
  999.                        Cust.Check3);
  1000.           CheckAddItem(10, 1,4, 'Woman Owned','',0,Cust.Check4);
  1001.           CheckRadioSetActive(10,3,false);
  1002.           SetLabel(10,LabelTop,LabelTop,'~B~usiness Categeory');
  1003.           SetHK(10,304);
  1004.  
  1005. List Fields
  1006.  
  1007.           Gold supports basic list fields that can be created and
  1008.      defined in a couple of fields, as well as gut-busting lists which
  1009.      have all the power of the list engine defined in the GoldLIST unit.
  1010.  
  1011. Basic List Fields
  1012.  
  1013.           Creating a list field is a two step process. First use
  1014.      ListField (described below) to define the overall dimensions of the
  1015.      list.
  1016.  
  1017.      ListField(FieldID,width,depth:byte; var SelectedItem:integer);
  1018.  
  1019.           Identfies the width and depth of a list field. The
  1020.      SelectedItem variable will be updated with the one-based node
  1021.      number of the selected item.
  1022.  
  1023.           Individual items in the list can be added using the
  1024.      ListAddItem function, which is defined as follows:
  1025.  
  1026.      ListAddItem(FieldID:integer; Str:string);
  1027.  
  1028.      Adds the specified string to the list. That's all there is to it.
  1029.  
  1030.           If you want to add a set of fields in one fell swoop, use the
  1031.      ListKwikAddItem as follows:
  1032.  
  1033.      ListKwikAddItem(FieldID:integer; Str:string);
  1034.  
  1035.           Adds a series of items to a list field. All the items are
  1036.      passed in a single string, and the items are separated with the
  1037.      split bar character "|".
  1038.  
  1039.      The following code fragment shows KwikListAddItem in use:
  1040.  
  1041.           SpinDropListField(1,25,PrintInfo.TypeFaceID);
  1042.           ListKwikAddItem(1,'Adelaide|Arial MT|Bookman|Courier'
  1043.                      ListKwikAddItem(1,'Dom Casual |Freestyle|Script');
  1044.           ListKwikAddItem(1,'Helvetica|Juniper|Kidnap|Lithos');
  1045.           ListKwikAddItem(1,'Light|Times Roman|Zap Dingbobs');
  1046.  
  1047.           In addition to the standard rectangular list box, Gold can
  1048.      display lists using formats similar to the Window's ComboBox. Lists
  1049.      can be displayed in a drop-down box, as a spinner field, or both
  1050.      features can be combined into a single spin drop list field. These
  1051.      different formats can be implemented by using one of the following
  1052.      three procedures in place of the standard ListField procedure:
  1053.  
  1054.           DropListField(FieldID,width:byte; var SelectedItem:integer);
  1055.           SpinListField(FieldID,width:byte; var SelectedItem:integer);
  1056.           SpinDropListField(FieldID,width:byte;
  1057.                                             var SelectedItem:integer);
  1058.  
  1059.           Use the EditDropListField (defined below) if you want the user
  1060.      to be able to type text into the field or optionally select the
  1061.      text from a drop-down list box.
  1062.  
  1063.      EditDropListField(FieldID:byte; var Strvar:string;
  1064.                                                       FieldL,MaxL:byte);
  1065.  
  1066.           To change the contents of a list field "on the fly", you
  1067.      should call ListRebuild (defined below) and pass the list contents
  1068.      as a single string using the KwikAddField format.
  1069.  
  1070.      ListRebuild(FieldID:integer; Str:string);
  1071.  
  1072.           If you want to get the literal string of the list items
  1073.      selected by the user, you can use the ListGetString function which
  1074.      is defined as follows:
  1075.  
  1076.      ListGetString(FieldID:integer; EntryNo:integer): string;
  1077.  
  1078. Power List Fields
  1079.  
  1080.           To display lists in forms which have advanced features such as
  1081.      tagging, wrapping, etc., you'll need to create a string linked
  1082.      list, and then use one of the power list fields. The power list
  1083.      fields use the list engine defined in the GoldLIST unit. We suggest
  1084.      you also read Chapters 14 and 15 to gain a thorough understanding
  1085.      of Gold's power field support.
  1086.  
  1087.           To display a list defined in an StrLL (a simple string linked
  1088.      list), first create the field using ListField, SpinDropListField
  1089.      (or any of the other variations) and then use ListAssignStrLL to
  1090.      define the list contents.
  1091.  
  1092.      ListAssignStrLL(FieldID:integer; var SL:StringLL);
  1093.  
  1094.           To change the list contents "on the fly", use the following
  1095.      procedure in preference to ListRebuild:
  1096.  
  1097.      ListUpdateStrLL(FieldID:integer; var SL:StringLL);
  1098.  
  1099.           The most powerful list fields provide all the functionality of
  1100.      Gold's list windows as a field in a form. Before adding the list
  1101.      field to the form, using one of the three procedures listed below,
  1102.      first create a linked list and a ListCfg variable following the
  1103.      same principles as outlined in Chapter 14.
  1104.  
  1105.      WrapListField(FieldID,Colwidth,ColCount,RowCount:byte;
  1106.                                               var ListDetails: ListCfg);
  1107.      GridListField(FieldID,width,depth:byte;var ListDetails: ListCfg);
  1108.      BrowseField(FieldID,width,depth:byte; var ListDetails: ListCfg);
  1109.  
  1110.           Use the following two functions to ascertain the user's
  1111.      selection from one of these power fields, along with the last key
  1112.      that was pressed when the list had focus in the form:
  1113.  
  1114.      ListGetActivePick(FieldID:integer): integer;
  1115.      ListLastKey(FieldID:byte):word;
  1116.  
  1117. Multi-Line Edit Fields
  1118.  
  1119.           Chapter 15 described how to use Gold's editor to add editing
  1120.      capabilities to an application. The same editor engine can be
  1121.      accessed from a form by using a memo field. It goes without saying
  1122.      that you need to read Chapter 15 to get the most out of the memo
  1123.      field.
  1124.  
  1125.           To add a memo field to a form, create a memo data source, such
  1126.      as a linked list, create and set a MemoCfg variable and then call
  1127.      MemoField, which is defined as follows:
  1128.  
  1129.      MemoField(FieldID,width,depth:byte;var Memo:MemoCfg);
  1130.  
  1131. Hot Spots
  1132.  
  1133.      When is a field not a field? When it's a hotspot!
  1134.  
  1135.           A hot spot field is really an invisible button. When you click
  1136.      on a hot spot, Gold will end the form edit session and return the
  1137.      gAction code assigned to the hotspot. Define a hot spot field using
  1138.      the following procedure:
  1139.  
  1140.      HotspotField(FieldID:byte; Width,Depth: byte; Action:gAction);
  1141.  
  1142.           Although the field seems to have little value, you can use it
  1143.      in conjunction with plain text to create custom buttons. For
  1144.      example, you might draw four different boxes on the form and write
  1145.      some text within each box. These text boxes are not active parts of
  1146.      the form, but by adding hotspots which overlay the precise area of
  1147.      the box, you can respond to user clicks in the rectangle.
  1148.  
  1149. Running The Form
  1150.  
  1151. Using EditForm
  1152.  
  1153.           Once the form has been fully defined, use the EditForm
  1154.      function to pass control to the user and let them get on with the
  1155.      input. EditForm is defined as follows:
  1156.  
  1157.      EditForm(StartField:byte):gAction;
  1158.  
  1159.           Displays the active form and allows the user to edit data in
  1160.      the fields. The single passed parameter indicates the FieldID of
  1161.      the field which will be initially focused when the edit session
  1162.      begins. The function returns a value of type gAction indicating how
  1163.      the edit session was terminated. This may be Finished, Escaped, or
  1164.      any of the codes assigned to buttons on the form.
  1165.  
  1166.           You should check the value returned by EditForm to determine
  1167.      whether the user was aborting, or  the user wanted the edits
  1168.      committed.
  1169.  
  1170.      The following code fragment illustrates this technique:
  1171.  
  1172.           if EditForm(1) = Finished then
  1173.              SaveTheEdits
  1174.           else
  1175.              IgnoreTheEdits;
  1176.  
  1177.           The function FieldWithFocus returns the FieldID of the field
  1178.      with focus. If you are using EditForm in a loop, use FieldWithFocus
  1179.      to determine which field to give focus on the next iteration. The
  1180.      following code fragment (extracted from DEMDB1.PAS) demonstrates
  1181.      this technique:
  1182.  
  1183.           ActiveField := 13;
  1184.           repeat
  1185.              RecNum := X;
  1186.              if (DbGetNumRecs > 0) and (X > 0) then
  1187.                 DatabaseToScreen(X);
  1188.              DisplayAllFields;
  1189.              LastAction := EditForm(ActiveField);
  1190.              ActiveField := FieldWithFocus;
  1191.              case LastAction of
  1192.                 Stop1: begin
  1193.                           X := NdxGotoFirst;
  1194.                           ActiveField := 13;  { next }
  1195.                        end;
  1196.                 Stop2: begin
  1197.                           X := NdxGotoPrev;
  1198.                           if X = 0 then
  1199.                           begin
  1200.                              X := NdxGotoLast;
  1201.                              PromptOK(' Top of file ','^Loop...')
  1202.                           end;
  1203.                        end;
  1204.                 Stop3: begin
  1205.                           X := NdxGotoNext;
  1206.                           if X = 0 then
  1207.                           begin
  1208.                              X := NdxGotoFirst;
  1209.                              PromptOK(' End of file ','^Loo...');
  1210.                           end;
  1211.                        end;
  1212.                 Stop4: begin
  1213.                           X := NdxGotoLast;
  1214.                           ActiveField := 12;  { prev }
  1215.                        end;
  1216.              end;  { case }
  1217.           until LastAction = Escaped;
  1218.           DisposeFields;
  1219.           DisposeForms;
  1220.  
  1221.           Old TTTimers might be familiar with the TTT5 procedure
  1222.      ProcessInput. This procedure is still supported. The function
  1223.      FormExitAction can be called to determine gAction value used to end
  1224.      the edit session.
  1225.  
  1226. Displaying The Form
  1227.  
  1228.           EditForm will automatically display the fields and labels in
  1229.      the form before commencing with the edit session. You can, however,
  1230.      display the form without passing control to the user by call the
  1231.      DisplayForm procedure, which is defined as follows:
  1232.  
  1233.      DisplayForm;
  1234.  
  1235.           Instructs Gold to display all the fields and labels associated
  1236.      with the active form.
  1237.  
  1238.           Behind the scenes, DisplayForm calls the two procedures
  1239.      DisplayAllLabels and DisplayAllFields. You can call these
  1240.      procedures individually if you prefer. For example, within an edit
  1241.      loop, you might want to call DisplayAllfields with each iteration
  1242.      of the loop because the data in the fields change each time around
  1243.      (see the code fragment on the previous page), but you might only
  1244.      call DisplayAllLabels once before starting the loop.
  1245.  
  1246. Closing and Disposing of a Form
  1247.  
  1248.           Behind the scenes, forms are created on the heap in a custom
  1249.      form of linked list. You must dispose of the memory used by a form
  1250.      when the form is no longer required.
  1251.  
  1252.           The primary way to dispose of a form is to call the procedure
  1253.      DisposeFields. This procedure will remove all the field data from
  1254.      memory and effectively erase all information associated with the
  1255.      active table.
  1256.  
  1257.           If you have called DisposeFields for a table, you can (at a
  1258.      later time) redefine the table with a new set of fields.
  1259.  
  1260. Using DisposeForms
  1261.  
  1262.           Gold maintains a list of information about each form, e.g.
  1263.      whether the form has any fields defined, is the form in a window,
  1264.      etc. When you have no further need for any of the forms, you can
  1265.      call DisposeForms to free every last drop of memory used by the
  1266.      forms.
  1267.  
  1268. Using Hooks in Forms
  1269.  
  1270.           Brilliant though Gold is, there will be occasions when the
  1271.      form routines provided do not meet your exact requirements. There
  1272.      are six different custom hooks which will allow you to precisely
  1273.      customize a form's behavior to meet your specific needs.
  1274.  
  1275.           The hooks provide you with information about the current state
  1276.      of the form and the task being performed, and allow you to
  1277.      influence the execution of the task. For example, the user may be
  1278.      attempting to leave field 2 (perhaps by pressing the tab key or
  1279.      clicking with the mouse on another field). You could use a leave
  1280.      field hook to trap for the field change event, and only permit the
  1281.      user to leave field 2 when the data in the field is satisfactory.
  1282.  
  1283.      Gold provides the following form hooks:
  1284.  
  1285.           Character Hook
  1286.                Called every time the user presses a character.
  1287.  
  1288.           Hind Hook
  1289.                Called after a every character has been processed.
  1290.  
  1291.           Insert Hook
  1292.                Called when the user presses the insert key.
  1293.  
  1294.           Leave Field Hook
  1295.                Called every time the user tries to leave one field and
  1296.                move to another.
  1297.  
  1298.           Enter Fields Hook
  1299.           Called every time the user tries to enter a field, i.e. gives
  1300.           a field focus.
  1301.  
  1302.           Finished Hook
  1303.                Called when the user tries to close the form.
  1304.  
  1305. Intercepting Every Character
  1306.  
  1307.           Two different hooks allow you to trap each character as it is
  1308.      processed. The character hook gives you a chance to review a
  1309.      character before it is processed by Gold, and the Hind hook is
  1310.      called after each character has been processed.
  1311.  
  1312. Character Hook
  1313.  
  1314.           For a procedure to be eligible as a form character hook, it
  1315.      must adhere to the following rules:
  1316.  
  1317.           The function must be declared as a far function at the root
  1318.           level. Refer to section Understanding Hooks in Chapter 3 for
  1319.           further information.
  1320.  
  1321.           The function must be declared with three passed parameters.
  1322.           The first parameter is a variable word parameter which
  1323.           indicates the key which is about to be processed. The second
  1324.           parameter is a variable byte parameter, indicating the ID of
  1325.           the field with focus. The third parameter is also a variable
  1326.           of type byte which can be used to return a Refresh code,
  1327.           instructing Gold on how to proceed.
  1328.  
  1329.      The following procedure declaration follows these rules:
  1330.  
  1331.           {$F+}
  1332.           procedure KeyPressCheck(var C : word;var CF:byte;
  1333.                                                       var Refresh:byte);
  1334.           begin
  1335.               If C = 315 then
  1336.               begin
  1337.                   Help;
  1338.                   C := 0;
  1339.               end;
  1340.           end;
  1341.           {$F-}
  1342.  
  1343.           The following procedure is then called to instruct Gold to
  1344.      call your procedure every time a character is about to be
  1345.      processed:
  1346.  
  1347.      AssignCharHook(Proc:CharHookProc);
  1348.  
  1349.      Here are a few tips about writing character hooks:
  1350.  
  1351.           If you want to trap for a special character (such as Alt-H),
  1352.      perform some custom task, and then stop Gold from trying to process
  1353.      this character, assign a value of zero to the character and Gold
  1354.      will ignore it.
  1355.  
  1356.           The Refresh parameter is used to instruct Gold to perform some
  1357.      special screen refreshing task. The constants (listed below) are
  1358.      declared in the GoldIO unit and should be used for this purpose.
  1359.      Assign one of these values to the third passed parameter if you
  1360.      want Gold to perform some special field refreshing operation, or if
  1361.      you want to end the edit session.
  1362.  
  1363.           RefreshNone    = 0;
  1364.           RefreshCurrent = 1;
  1365.           RefreshAll     = 2;
  1366.           RefreshOthers  = 3;
  1367.           EndInput       = 99;
  1368.  
  1369. Hind Hook
  1370.  
  1371.           Like the character hook, the hind hook is called every time a
  1372.      key is pressed by the user. The hind hook, however, is called after
  1373.      the character has been processed by Gold. One use for a hind hook
  1374.      provides is to write some text to the screen based on the data
  1375.      entered into other fields; the sub-totals on an invoice form, for
  1376.      example. A hind hook is often used to change the enabled/disabled
  1377.      state of a field based on the value of other fields, e.g. if a font
  1378.      check box is not checked, then the hind hook might disable or hide
  1379.      the font list box.
  1380.  
  1381.           For a procedure to be eligible as a form character hook, it
  1382.      must adhere to the following rules:
  1383.  
  1384.           The function must be declared as a far function at the root
  1385.           level. Refer to section Understanding Hooks in Chapter 3 for
  1386.           further information.
  1387.  
  1388.           The function must be declared with two passed parameters. The
  1389.           first parameter is a byte parameter indicating the ID of the
  1390.           field with focus. The second parameter is a variable of type
  1391.           byte which can be used to return a Refresh code, instructing
  1392.           Gold on how to proceed.
  1393.  
  1394.      The following procedure declaration follows these rules:
  1395.  
  1396.           {$F+}
  1397.           procedure MyHindHook(CurrentField:byte;var Refresh:byte);
  1398.           {}
  1399.           begin
  1400.              Refresh := RefreshNone;
  1401.              if CurrentField = 9 then {radio button}
  1402.              begin
  1403.                 if (Cust.Radio = 4)
  1404.                 and (FieldGetState(10) = FldOn) then
  1405.                 begin
  1406.                    FieldSetState(10,FldOff);
  1407.                    Refresh := RefreshOthers;
  1408.                 end
  1409.                 else if (Cust.Radio <> 4)
  1410.                 and not (FieldGetState(10) = FldOn) then
  1411.                 begin
  1412.                    FieldSetState(10,FldOn);
  1413.                    Refresh := RefreshOthers;
  1414.                 end;
  1415.              end;
  1416.           end; {MyHindHook}
  1417.           {$F-}
  1418.  
  1419.           The following procedure is then called to instruct Gold to
  1420.      call your procedure every time a character has been processed:
  1421.  
  1422.      AssignHindHook(Proc:HindHookProc);
  1423.  
  1424.           The demo program DEMIO6.PAS shows a hind hook being used to
  1425.      enable and disable fields.
  1426.  
  1427. Insert Hook
  1428.  
  1429.           The insert hook is called every time the user presses the
  1430.      insert key. By default, Gold sets the cursor to a full block in
  1431.      overtype mode, and an underscore in insert mode. The hook allows
  1432.      the programmer to introduce some other method of indicating the
  1433.      insert status, e.g. writing "insert" or "replace" somewhere on the
  1434.      screen.
  1435.  
  1436.           For a procedure to be eligible as a insert hook, it must
  1437.      adhere to the following rules:
  1438.  
  1439.           The function must be declared as a far function at the root
  1440.           level. Refer to section Understanding Hooks in Chapter 3 for
  1441.           further information.
  1442.  
  1443.           The function must be declared with one boolean parameter. This
  1444.           parameter indicates the new state of the insert key.
  1445.  
  1446.      The following procedure declaration adheres to these rules:
  1447.  
  1448.           {$F+}
  1449.           procedure MyInsHook(Insert:boolean);
  1450.           begin
  1451.              ...
  1452.           end;
  1453.           {$F-}
  1454.  
  1455.           The following procedure is then called to instruct Gold to
  1456.      call your procedure every time the insert key is pressed:
  1457.  
  1458.      AssignInsHook(Proc:InsProc);
  1459.  
  1460.  
  1461. Field Changing Hooks
  1462.  
  1463.           Gold provides leave field and enter field hooks. These
  1464.      functions are called when the user tries to leave a field, and when
  1465.      the user tries to enter a field. The leave field hook provides a
  1466.      way to ensure that the contents of a field are valid before moving
  1467.      to another field. The enter field hook can be used to take some
  1468.      action before entering a field, e.g. display a warning message, or
  1469.      move the user to another field if a specific condition is not met.
  1470.  
  1471.           You declare leave field and enter field hooks in the same way,
  1472.      i.e. they accept the same arguments. For a procedure to be eligible
  1473.      as a leave or enter field hook, it must adhere to the following
  1474.      rules:
  1475.  
  1476.           The procedure must be declared as a far function at the root
  1477.           level. Refer to section Understanding Hooks in Chapter 3 for
  1478.           further information.
  1479.  
  1480.           The procedure must be declared with two variable byte
  1481.           parameters. The first parameter indicates the ID of the field
  1482.           which the user is about to leave or enter. The second
  1483.           parameter is a refresh code which may be updated to instruct
  1484.           Gold to either terminate the edit session or refresh one or
  1485.           more fields. You can use one of the following constants to
  1486.           indicate the appropriate refresh action:
  1487.  
  1488.                RefreshNone    = 0;
  1489.                RefreshCurrent = 1;
  1490.                RefreshAll     = 2;
  1491.                RefreshOthers  = 3;
  1492.                EndInput       = 99;
  1493.  
  1494.           One of the following two procedures can then be used to
  1495.      instruct Gold to call your procedure every time the user tries to
  1496.      leave or enter a field, respectively:
  1497.  
  1498.      AssignLeaveFieldHook(Proc:MoveFieldProc);
  1499.      AssignEnterFieldHook(Proc:MoveFieldProc);
  1500.  
  1501. The Leave Field Hook
  1502.  
  1503.           As mentioned earlier, leave field hooks are often used to add
  1504.      some custom field's validation. For example, you might want to
  1505.      check that a filename field contains a valid filename. When you
  1506.      find that a field input is not valid, you can force the user to
  1507.      stay in the same field (i.e. stop changing focus) by setting the
  1508.      Field ID parameter to a value of zero.
  1509.  
  1510.           Listed below is an example of a leave field hook, which
  1511.      displays an error message and keeps the user in the same field when
  1512.      the field contains an odd number. (OK, it's a contrived example,
  1513.      but you get the idea!)
  1514.  
  1515.           {$F+}
  1516.           procedure MyLeaveHook(var CurrentField:byte;var Refresh:byte);
  1517.           {}
  1518.           begin
  1519.              if (CurrentField = 3)
  1520.              and odd(DressSize) then
  1521.              begin
  1522.                 PromptOK(' Error ','The dress size must be an
  1523.                                     even number,e.g. 4,6,8...');
  1524.                 CurrentField := 0;
  1525.              end;
  1526.           end;
  1527.           {$F-}
  1528.  
  1529. The Enter Field Hook
  1530.  
  1531.           An enter field hook is called every time the user changes
  1532.      focus to a new field. In fact, the hook is called just before the
  1533.      focus is changed, and so the hook can redirect the focus to a
  1534.      different field. If you want to direct the focus to a different
  1535.      field, just assign a new value to the Field ID parameter.
  1536.  
  1537.           Traditionally, enter field hooks were used to temporarily
  1538.      disable fields, i.e. to prevent a user from giving a field focus.
  1539.      Gold now offers the FieldSetState function as a quick and easy way
  1540.      to disable the field, so the primary need for an enter field hook
  1541.      has disappeared.
  1542.  
  1543.           Gold can display a context sensitive message when the user
  1544.      moves from field to field, but only a single line of text can be
  1545.      displayed. A good application for an enter field hook is to display
  1546.      custom multi-line help giving the user instructions relevant to the
  1547.      field with focus. The following code fragment shows how this could
  1548.      be done:
  1549.  
  1550.           {$F+}
  1551.           procedure MyEnterHook(var CurrentField:byte;var Refresh:byte);
  1552.           {}
  1553.           begin
  1554.              case CurrentField of
  1555.                 1: begin
  1556.                    WriteAT(.....
  1557.                    WriteAT(.....
  1558.                    WriteAT(.....
  1559.                 end;
  1560.                 3: begin
  1561.                    WriteAT(.....
  1562.                    WriteAT(.....
  1563.                    WriteAT(.....
  1564.                 end;
  1565.                 ...
  1566.              end; {case}
  1567.           end;
  1568.           {$F-}
  1569.  
  1570. The Finished Hook
  1571.  
  1572.           The leave field hook provides a way to implement custom
  1573.      validation on a field by field basis. The finish hook, however,
  1574.      provides a way to implement complete validation when the user tries
  1575.      to end the edit session (other than by escaping).
  1576.  
  1577.           The finish hook is called after all Gold's internal validation
  1578.      routines have been performed. It provides the user with one last
  1579.      chance to check all the edits before the form is closed.
  1580.  
  1581.           For a function to be eligible as a finished hook, it must
  1582.      adhere to the following rules:
  1583.  
  1584.           The function must be declared as a far function at the root
  1585.           level. Refer to section Understanding Hooks in Chapter 3 for
  1586.           further information.
  1587.  
  1588.           The function must be declared no passed parameters, and must
  1589.           return a byte value.
  1590.  
  1591.           The hook function returns the ID of the field which failed
  1592.      validation. If the function returns a zero, Gold will close the
  1593.      form. If the function returns a non-zero value, the edit session
  1594.      will continue and focus will shift to the Field whose ID matches
  1595.      the value returned by the hook function.
  1596.  
  1597.           Having declared the hook function, instruct Gold to call your
  1598.      procedure every time the user tries to close the form by calling
  1599.      the following procedure:
  1600.  
  1601.      AssignFinishedHook(Proc:FinishedProc);
  1602.  
  1603.           The following example shows a finished hook which makes sure
  1604.      that the first field is not null if the second field (a check box
  1605.      field) is checked.
  1606.  
  1607.           {$F+}
  1608.           function CheckNullState:byte;
  1609.           {}
  1610.           begin
  1611.              if (PrinterHeader = true)
  1612.              and (Heading = '') then
  1613.              begin
  1614.                 PromptOK(' Error ','Heading Field cannot be empty
  1615.                                     when print is checked');
  1616.                 CheckNullState := 1
  1617.              end
  1618.              else
  1619.                 CheckNullState := 0;
  1620.           end;
  1621.           {$F+}
  1622.  
  1623.  
  1624. Launching Forms on the Desktop
  1625.  
  1626.           All forms displayed on the desktop must be displayed in a
  1627.      window. However, in place of the procedure SetFormWindow (discussed
  1628.      earlier), a desktop form must be initialized with the
  1629.      LaunchFormInit function which is described below:
  1630.  
  1631.      LaunchFormInit(X1,Y1,X2,Y2,style:byte;
  1632.                                           CloseProc:FormCloseProc):byte;
  1633.  
  1634.           Initializes a form for use on the desktop. The first five
  1635.      parameters define the windows coordinates and style, respectively.
  1636.      The last parameter is the name of a function which will be called
  1637.      when the window containing the form is about to be removed from the
  1638.      desktop. LaunchFormInit returns the handle (or number) of the
  1639.      window which will contain the form.
  1640.  
  1641.           Once the form is initialized, the standard IO routines can be
  1642.      called in the normal manner, e.g. KwikAddField, DateField, etc.
  1643.  
  1644.           When the form has been fully defined, you launch the form
  1645.      (i.e. make it visible on the desktop) by calling the LaunchForm
  1646.      procedure which is described as follows:
  1647.  
  1648.      LaunchForm(StartField:byte);
  1649.  
  1650.           Displays the form window on the desktop. The single passed
  1651.      parameter identifies the FieldID of the field which will have focus
  1652.      when the form is first displayed.
  1653.  
  1654. Understanding the FormCloseProc
  1655.  
  1656.           By design, a form launched on the desktop is non-modal, i.e.
  1657.      the user can change focus from a form to any other window on the
  1658.      desktop. The user may close the form at any time using a variety of
  1659.      methods. The user might click on the OK button on the form, click
  1660.      on the close icon, or select Close Window from the desktop menu.
  1661.      Since the desktop is event driven, you have to "wait" for the form
  1662.      to be closed before using the data entered into the form, calling
  1663.      DisposeFields and performing all the other necessary house-keeping
  1664.      duties.
  1665.  
  1666.           When you prepare a form for use on the desktop (using
  1667.      LaunchFormInit), you must specify the name of a function declared
  1668.      to be of type FormCloseProc, which is declared as follows:
  1669.  
  1670.         FormCloseProc = function(FormID: byte):boolean;
  1671.  
  1672.           This function will be called by Gold when the user attempts to
  1673.      close the form. This is your chance to do the housekeeping duties
  1674.      which you would normally perform after a call to EditForm (in a
  1675.      non-desktop application). The function returns a boolean to
  1676.      indicate to Gold whether the form may be closed. If a FALSE value
  1677.      is returned, the form window will not be closed.
  1678.  
  1679.           For a function to be eligible as a form close function it must
  1680.      adhere to the following rules:
  1681.  
  1682.           The function must be declared as a far function at the root
  1683.           level. Refer to section Understanding Hooks in Chapter 3 for
  1684.           further information.
  1685.  
  1686.           The function must be declared with a single passed parameter
  1687.           of type byte and return a boolean indicating whether the form
  1688.           can be closed. The passed parameter indicates the window
  1689.           handle (or number) of the window that is being closed.
  1690.  
  1691.           The following function declaration (extracted from
  1692.      DEMDESK4.PAS) follows these rules:
  1693.  
  1694.           {$F+}
  1695.           function FormShutDown(Form:byte):boolean;
  1696.           {}
  1697.           begin
  1698.              BarSetActive(MainMenu,200,true);
  1699.              DeskRefreshBgnd;
  1700.              DisposeFields;
  1701.              DisposeForms;
  1702.              PrintInfo.TypeSize := Longvar;
  1703.              FormShutDown := true;
  1704.           end; { FormShutDown }
  1705.           {$F-}
  1706.  
  1707.           Review the demo program DEMDESK4.PAS for a complete example of
  1708.      using forms in a desktop application.
  1709.  
  1710.           var
  1711.              Name,Tel:string;
  1712.              Age:byte;
  1713.              Sex: string[1];
  1714.              Result: gAction;
  1715.  
  1716.           procedure SetScreen;
  1717.           {}
  1718.           begin
  1719.             ...
  1720.           end; { SetScreen }
  1721.  
  1722.           procedure SetVars;
  1723.           begin
  1724.              Name := '';
  1725.              Tel := '';
  1726.              Age  := 0;
  1727.              Sex := '';
  1728.           end; { SetVars }
  1729.  
  1730.           procedure SetFields;
  1731.           begin
  1732.              {create the 5 fields}
  1733.              KwikAddField(1, 25,9);   {Field 1, column 25, line 9}
  1734.              KwikAddField(2, 25,11);  {Field 2, column 25, line 11}
  1735.              KwikAddField(3, 25,13);  {Field 3, column 25, line 13}
  1736.              KwikAddField(4, 25,15);  {Field 4, column 25, line 15}
  1737.              KwikAddField(5, 26,18);  {Field 5, column 25, line 18}
  1738.              KwikAddLastField(6, 43,18); {Field 6, column 43, line 18}
  1739.              {Field 1}
  1740.              StringField(1, Name, '******************************');
  1741.              SetLabel(1, LabelLeft,LabelLeft,'Full name:');
  1742.              {Field 2}
  1743.              StringField(2, Tel, '(###) ###-####');
  1744.              SetLabel(2, LabelLeft,LabelLeft,'Tel:');
  1745.              {Field 3}
  1746.              ByteField(3, Age, '##', 13,65);
  1747.              SetLabel(3, LabelLeft,LabelLeft,'Patients age:');
  1748.              {Field 4}
  1749.              StringField(4, Sex, '!');
  1750.              SetLabel(4, LabelLeft,LabelLeft,'Sex:');
  1751.              {Fields 4 & 5: buttons}
  1752.              ButtonField(5,'   OK   ',finished);
  1753.              ButtonField(6,' Cancel ',escaped);
  1754.           end; { SetFields }
  1755.  
  1756.           begin
  1757.              SetScreen;
  1758.              SetVars;
  1759.              SetFields;
  1760.              SetValidation(ValidateAtEnd);
  1761.              MouseShow(true);
  1762.              Result := EditForm(1);
  1763.              GotoXY(1,25);
  1764.              DisposeFields;
  1765.              DisposeForms;
  1766.              ...
  1767.           end.
  1768.  
  1769.           Specify the field properties, and associate the field with a
  1770.      variable.
  1771.  
  1772. Add labels to the fields.
  1773.  
  1774.      Add the fields to the form and define their order and location
  1775.  
  1776.      Initialize the variables that are going to be used in the form
  1777.  
  1778. Run the form.
  1779.  
  1780.      Dispose of everything when the form is no longer needed.
  1781.